package com.ooono.factorytest.items;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;

import com.ooono.factorytest.R;
import com.ooono.factorytest.base.BaseActivity;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class MainMicTestActivity extends BaseActivity {

    private static final String TAG = "MicTestFragment";

    public static final String KEY = "main_mic";

    private ProgressBar volumeBarPb;
    private TextView volumeValueTv;
    private Button mRecordPlayBtn;

    private static final int SAMPLE_RATE_DEFAULT = 16000; // 16KHz
    private static final int PCM_CHANNELS = 1; // 1通道
    private static final int PCM_ENCODING_FORMAT = 16; // 16bit

    private boolean isRecording = false;
    private int mRecordBufferSize;
    private AudioRecord mAudioRecord;
    private AudioTrack mAudioTrack;
    private String mRecordFilePath;

    @Override
    public int getTestTitle() {
        return R.string.test_item_main_mic;
    }

    @Override
    public String getTestKey() {
        return KEY;
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 创建文件路径
        mRecordFilePath = ContextCompat.getExternalFilesDirs(this,
                Environment.DIRECTORY_MUSIC)[0].getAbsolutePath() + File.separator + "record.pcm";

        // 创建AudioRecord
        mRecordBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE_DEFAULT,
                AudioFormat.CHANNEL_IN_MONO,
                AudioFormat.ENCODING_PCM_16BIT);
        mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE_DEFAULT,
                AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, mRecordBufferSize);

        // 创建AudioTrack
        int bufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE_DEFAULT,
                AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
        mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE_DEFAULT,
                AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT,
                bufferSize, AudioTrack.MODE_STREAM);
    }

    @Override
    public int getContentLayout() {
        return R.layout.content_mic_test;
    }

    @Override
    public void initViews() {

        volumeBarPb = findViewById(R.id.pb_volume_bar);
        volumeValueTv = findViewById(R.id.tv_volume_value);
        mRecordPlayBtn = findViewById(R.id.btn_record_play);

        mRecordPlayBtn.setOnClickListener(view -> {
            if (isRecording) {
                mRecordPlayBtn.setText(R.string.mic_test_record);
                play();
            } else {
                mRecordPlayBtn.setText(R.string.mic_test_play);
                record();
            }
        });
    }


    private void record() {
        Log.i(TAG, "record");

        isRecording = true;

        // 停止播放
        mAudioTrack.stop();

        // 开始录音
        mAudioRecord.startRecording();

        new Thread(() -> {
            File file = new File(mRecordFilePath);
            if (file.exists()) {
                file.delete();
            }

            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(mRecordFilePath);
                byte[] buffer = new byte[mRecordBufferSize];

                // 循环读取语音流（PCM数据包）
                while (mAudioRecord.read(buffer, 0, mRecordBufferSize) > 0) {
                    Log.d(TAG, "AudioRecord read: " + buffer.length);

                    // PCM数据保存到本地文件
                    fos.write(buffer);

                    mHandler.post(() -> {
                        volumeBarPb.setProgress((int) Math.abs((calculateVol(buffer) - 100)));
                        volumeValueTv.setText((int) Math.abs((calculateVol(buffer) - 100)) + " db");
                    });
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fos != null) {
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    private void play() {
        Log.i(TAG, "play");

        isRecording = false;

        // 停止录音
        mAudioRecord.stop();

        // 开始播放
        mAudioTrack.play();

        new Thread(() -> {
            File file = new File(mRecordFilePath);
            if (!file.exists()) {
                Log.e(TAG, "play, " + mRecordFilePath + " not exist");
                return;
            }

            long fileSize = file.length();
            if (fileSize > Integer.MAX_VALUE) {
                Log.w(TAG, "play, file too big");
                fileSize = Integer.MAX_VALUE;
            }

            try (FileInputStream fis = new FileInputStream(mRecordFilePath)) {
                int size;
                byte[] buffer = new byte[mRecordBufferSize];
                while ((size = fis.read(buffer, 0, mRecordBufferSize)) >= 0) {
                    if (mAudioTrack.getPlayState() == 3) {
                        Log.d(TAG, "AudioTrack write: " + size + "/" + fileSize);

                        // PCM数据写入AudioTrack中播放
                        mAudioTrack.write(buffer.clone(), 0, size);
                    }
                }
            } catch (IOException e) {
                Log.e(TAG, "AudioTrack write error: " + e.getMessage());
            }
        }).start();
    }

    private double calculateVol(byte[] buffer) {
        long v = 0;
        int value;
        int frame = buffer.length / (PCM_CHANNELS * PCM_ENCODING_FORMAT / 8);
        for (int i = 0; i < frame; i += (PCM_CHANNELS * PCM_ENCODING_FORMAT / 8)) {
            value = buffer[i];
            value = (value << 8) | buffer[i + 1];
            v += (long) value * value;
        }
        double mean = v / (double) frame;
        return 10 * Math.log10(mean);
    }

    @Override
    protected void onDestroy() {
        mAudioTrack.stop();
        mAudioTrack.release();

        mAudioRecord.stop();
        mAudioRecord.release();

        File file = new File(mRecordFilePath);
        if (file.exists()) {
            file.delete();
        }
        super.onDestroy();
    }
}